// 调度实际任务
class schedulerTask {
  constructor(task, id) {
    /**
     * 当前任务
     *
     * @type {Promise<void>}
     */
    this.task = task;
    /**
     * 任务id
     *
     * @type {Number}
     */
    this.id = id;
  }

  run() {
    this.task().then(() => console.log(`${this.id} 执行结束`));
  }
}

// 调度器
class TaskScheduler {
  constructor(maxNum = 2) {
    // 最大可执行任务数量
    this.maxNum = maxNum;
    /**
     * 等待任务队列
     *
     * @type {schedulerTask[]}
     */
    this.waitTasks = [];
    /**
     * 正在执行任务队列
     *
     * @type {schedulerTask[]}
     */
    this.runTasks = [];
    // 任务标记id
    this.taskID = 0;
  }

  /**
   * 任务封装
   *
   * @param {Promise<void} task
   * @param {Number} id
   * @returns
   */
  packagingTask(task, id) {
    const newTask = () =>
      new Promise((resolve) => {
        console.log("task 被执行", id);

        task().then(() => {
          // 删除运行队列中的task
          this.runTasks = this.runTasks.filter((t) => t.id !== id);

          // 如果运行队列不为空 且 任务执行结束后 任务数量不为 0  则执行下一个任务
          if (this.runTasks.length < this.maxNum && this.waitTasks.length > 0) {
            const nextTask = this.waitTasks.shift();
            this.runTasks.push(nextTask);
            console.log("开始执行等待队列", nextTask.id);

            nextTask.run();
          }
          resolve();
        });
      }).then(() => {
        console.log("任务被执行");
      });
    return new schedulerTask(newTask, id);
  }
  /**
   * 添加任务
   *
   * @param {Promise<void>} task
   * @returns {Number} 任务id
   */
  addTask(task) {
    const id = this.taskID++;

    const runTask = this.packagingTask(task, id);

    // 如果当前运行队列已满 则将任务添加到等待队列中
    if (this.runTasks.length >= this.maxNum) {
      this.waitTasks.push(runTask);
      console.log("追加等待中", id);
    } else {
      // 如果运行队列小于最大任务数 则直接执行
      this.runTasks.push(runTask);
      console.log("追加运行中", id);

      runTask.run();
    }
    return runTask.id;
  }

  /**
   * 任务删除
   *
   * @param {Number} id
   */
  delTask(id) {
    const oldTaskLength = this.waitTasks.length;
    this.waitTasks = this.waitTasks.filter((t) => t.id !== id);
    const newTaskLength = this.waitTasks.length;
    if (oldTaskLength == newTaskLength) {
      console.log(`任务 ${id} 正在运行中 删除失败`);
    } else {
      console.log(`任务 ${id} 删除成功`);
    }
  }
}

const scheduler = new TaskScheduler();

function promiseTimeout(time, label) {
  console.time(label);
  return () =>
    new Promise((resolve) => {
      setTimeout(() => {
        resolve(label);
      }, time);
    }).then(() => {
      console.timeEnd(label);
    });
}

// 业务场景 商品列表中 点击商品将会进入详情页 为了实现详情页秒开 在用户点击前要预请求商品信息,
// 假设 有100条商品项目,如果同时发出100个请求可能会将带宽打满 部分设备可能还会有请求的限制,
// 这样会阻塞原本页面的请他正常请求 因此我们需要实现一个任务调度器 确保同时最多只有2个任务执行
// 一秒钟后输出 商品1
scheduler.addTask(promiseTimeout(1000, "商品1"));
// 两秒钟后输出 商品2
scheduler.addTask(promiseTimeout(2000, "商品2"));
// 四秒钟后输出 商品3
scheduler.addTask(promiseTimeout(3000, "商品3"));
// 六秒种后输出 商品4
const task4ID = scheduler.addTask(promiseTimeout(4000, "商品4"));
// console.log(task4ID);

// 任务删除
scheduler.delTask(task4ID);
